﻿using SqlSugar;
using System.Reflection;
using Zhp.Api.Attributes;
using Zhp.Common.Appsetting;
using Zhp.Common.Extention;
using Zhp.Common.Helper;
using Zhp.Common.Swagger;
using Zhp.Entity.Sys;
using Zhp.Entity.SysEnum;

namespace Zhp.Api.Middleware
{
    public static class SeedDataMiddleware
    {
        private static IApplicationBuilder _app;
        private static ISqlSugarClient _db;
        /// <summary>
        /// 初始化数据库和基本数据
        /// </summary>
        /// <param name="app"></param>
        public static void UseSeedDataMiddleware(this IApplicationBuilder app)
        {
            _app = app;
            _db = app.ApplicationServices.GetService<ISqlSugarClient>();

            if (_db == null) { throw new Exception("ISqlSugarClient service not found!"); }
            var options = AppSettingHelper.GetOptions<SysDataOptions>();
            if (options.InitDatabase)
            {
                //初始化表，不存在才会新增，已存在的不变
                ConsoleHelper.WriteLine($"数据库初始化....", ConsoleColor.Green);
                InitDatabase();
                ConsoleHelper.WriteLine($"数据库初始化成功", ConsoleColor.Green);
            }

            if (options.InitSeedData)
            {
                //初始化数据
                ConsoleHelper.WriteLine($"基础数据初始化....", ConsoleColor.Green);
                InitSeedData();
                ConsoleHelper.WriteLine($"基础数据初始化成功", ConsoleColor.Green);
            }
        }

        /// <summary>
        /// 初始化数据库
        /// </summary>
        private static void InitDatabase()
        {
            var program = AppSettingHelper.GetOptions<ProgramCodeOptions>();
            var assembly = Assembly.Load(program.EntityName);

            if (assembly == null) { throw new Exception($"{program.EntityName} assembly not found!"); }

            //创建库
            _db.DbMaintenance.CreateDatabase();

            //创建表
            var entities = assembly.GetTypes().Where(x => x.IsDefined(typeof(SugarTable))).ToArray();

            foreach (var entity in entities)
            {
                _db.CodeFirst.InitTables(entity);
            }
        }
        /// <summary>
        /// 初始化数据，多级菜单，页面配置，这里无法生成
        /// </summary>
        private static void InitSeedData()
        {
            var options = AppSettingHelper.GetOptions<SysDataOptions>();
            var userEntityList = _db.Queryable<SysUser>().ToList();
            var menuEntityList = _db.Queryable<SysMenu>().ToList();
            //用户，菜单，权限
            var userList = new List<SysUser> {
                new SysUser
                {
                    UserName = "root",
                    NickName = "超级管理员",
                    Password = options.DefaultPassword.ToSHA256String(),
                    Email = options.DefaultEmailAddress,
                    IsAdmin = true,
                    IsEnabled = true,
                    CreateTime = DateTime.Now,
                    IsDeleted = false,
                },
                new SysUser
                {
                    UserName = "admin",
                    NickName = "管理员",
                    Password = options.DefaultPassword.ToSHA256String(),
                    Email = options.DefaultEmailAddress,
                    IsAdmin = true,
                    IsEnabled = true,
                    CreateTime = DateTime.Now,
                    IsDeleted = false,
                },
                new SysUser
                {
                    UserName = "zhangsan",
                    NickName = "张三",
                    Password = options.DefaultPassword.ToSHA256String(),
                    Email = options.DefaultEmailAddress,
                    IsAdmin = false,
                    IsEnabled = true,
                    CreateTime = DateTime.Now,
                    IsDeleted = false,
                }
            };
            foreach (var item in userList)
            {
                var userEntity = userEntityList.FirstOrDefault(x => x.UserName == item.UserName);
                item.Id = userEntity == null ? SnowFlakeHelper.GetLongId() : userEntity.Id;
            }

            var seedList = new List<MenuSeedData>();
            var controllers = ControllerHelper.GetAllControllers(_app);
            foreach (var controller in controllers)
            {
                //按钮
                var methods = controller.GetMethods().Where(x => x.IsDefined(typeof(SeedButtonAttribute)));
                foreach (var method in methods)
                {
                    var methodAttribute = method.GetCustomAttribute<SeedButtonAttribute>();
                    var button = new MenuSeedData
                    {
                        Name = methodAttribute.Name,
                        MenuType = MenuTypeEnum.Button,
                        Controller = controller.Name.Replace("Controller", "").ToLower(),
                        Action = method.Name.ToLower(),
                        ExtraApiUrls = methodAttribute.ExtraApiUrls,
                        BelongGroup = methodAttribute.Group,
                        BelongMenu = methodAttribute.Menu,
                        BelongList = methodAttribute.List
                    };
                    seedList.Add(button);
                }

                //列表
                var lists = controller.GetMethods().Where(x => x.IsDefined(typeof(SeedListAttribute)));
                foreach (var listMethod in lists)
                {
                    var listAttribute = listMethod.GetCustomAttribute<SeedListAttribute>();
                    var list = new MenuSeedData
                    {
                        Name = listAttribute.Name,
                        MenuType = MenuTypeEnum.List,
                        Controller = controller.Name.Replace("Controller", "").ToLower(),
                        Action = listMethod.Name.ToLower(),
                        ExtraApiUrls = listAttribute.ExtraApiUrls,
                        BelongGroup = listAttribute.Group,
                        BelongMenu = listAttribute.Menu
                    };
                    seedList.Add(list);
                }

                //菜单
                var menuAttribute = controller.GetCustomAttribute<SeedMenuAttribute>();
                if (menuAttribute == null)
                {
                    continue;
                }
                var menu = new MenuSeedData
                {
                    Name = menuAttribute.Name,
                    MenuType = MenuTypeEnum.Menu,
                    RouterName = menuAttribute.RouterName.ToLower(),
                    WebFilePath = menuAttribute.WebFilePath,
                    Icon = menuAttribute.Icon,
                    Order = menuAttribute.Order,
                    BelongGroup = menuAttribute.MenuGroup
                };
                seedList.Add(menu);

                //分组
                var field = typeof(ApiGroupEnum).GetEnumFields().First(x => x.Name == menuAttribute.MenuGroup.ToString());
                if (field == null)
                {
                    continue;
                }
                var groupAttribute = field.GetCustomAttribute<ApiGroupEnumAttribute>();
                var groupName = groupAttribute.ApiGroupName;
                var groupIcon = groupAttribute.MenuIcon;
                var groupOrder = groupAttribute.Order;
                if(!seedList.Exists(x => x.MenuType == MenuTypeEnum.Group && x.Name == groupName))
                {
                    var group = new MenuSeedData
                    {
                        Name = groupName,
                        MenuType = MenuTypeEnum.Group,
                        RouterName = menuAttribute.MenuGroup.ToString().ToLower(),
                        Icon = groupIcon,
                        Order = groupOrder
                    };
                    seedList.Add(group);
                }
            }

            //根路由必须以/开头,一级分组必须是布局页面
            var menuList = new List<SysMenu>();
            var groupList = seedList.Where(x => x.MenuType == MenuTypeEnum.Group).ToList();
            foreach (var g in groupList)
            {
                var seedMenuList = seedList.Where(x => x.MenuType == MenuTypeEnum.Menu && x.BelongGroup.ToString().ToLower() == g.RouterName);
                var groupEntity = menuEntityList.FirstOrDefault(x => x.MenuType == MenuTypeEnum.Group && x.Name == g.Name);
                long groupId = groupEntity == null ? SnowFlakeHelper.GetLongId() : groupEntity.Id;
                var group = new SysMenu
                {
                    Id = groupId,
                    Name = g.Name,
                    MenuType = g.MenuType,
                    RouterName = g.RouterName,
                    RouterUrl = $"/{g.RouterName}",
                    WebFilePath = "Layout",//一级分组必须是布局页面
                    Icon = g.Icon,
                    Order = g.Order,
                    CreateTime = DateTime.Now,
                    CreateBy = userList.First().CreateBy,
                    HasChildren = seedMenuList.Any()
                };
                bool isRootMenu = group.RouterName == ApiGroupEnum.None.ToString().ToLower();
                if (!isRootMenu)
                {
                    menuList.Add(group);
                }

                //菜单
                foreach (var m in seedMenuList)
                {
                    var seedListList = seedList.Where(x => x.MenuType == MenuTypeEnum.List && x.BelongGroup == m.BelongGroup && x.BelongMenu == m.Name);
                    var menuEntity = menuEntityList.FirstOrDefault(x => x.MenuType == MenuTypeEnum.Menu && x.ParentId == (isRootMenu ? null : groupId) && x.Name == m.Name);
                    long menuId = menuEntity == null ? SnowFlakeHelper.GetLongId() : menuEntity.Id;
                    var menu = new SysMenu
                    {
                        Id = menuId,
                        ParentId = isRootMenu ? null : groupId,
                        Name = m.Name,
                        MenuType = m.MenuType,
                        RouterName = m.RouterName,
                        RouterUrl = isRootMenu ? $"/{m.RouterName}" : m.RouterName,
                        WebFilePath = m.WebFilePath,
                        Icon = m.Icon,
                        Order = m.Order,
                        CreateTime = DateTime.Now,
                        CreateBy = userList.First().CreateBy,
                        HasChildren = seedListList.Any()
                    };
                    menuList.Add(menu);

                    //列表
                    foreach (var li in seedListList)
                    {
                        var seedButtonList = seedList.Where(x => x.MenuType == MenuTypeEnum.Button && x.BelongGroup == m.BelongGroup && x.BelongMenu == m.Name && x.BelongList == li.Name);
                        var listEntity = menuEntityList.FirstOrDefault(x => x.MenuType == MenuTypeEnum.List && x.ParentId == menuId && x.Name == li.Name);
                        long listId = listEntity == null ? SnowFlakeHelper.GetLongId() : listEntity.Id;
                        var list = new SysMenu
                        {
                            Id = listId,
                            ParentId = menu.Id,
                            Name = li.Name,
                            MenuType = li.MenuType,
                            ApiUrl = $"/api/{li.Controller}/{li.Action}",
                            Permission = $"api:{g.RouterName}:{li.Controller}:{li.Action}",
                            Icon = li.Icon,
                            Order = li.Order,
                            CreateTime = DateTime.Now,
                            CreateBy = userList.First().CreateBy,
                            HasChildren = seedButtonList.Any()
                        };
                        if (li.ExtraApiUrls != null)
                        {
                            list.ApiUrl = string.Join(";", li.ExtraApiUrls.Append(list.ApiUrl));
                        }
                        menuList.Add(list);

                        //按钮
                        foreach (var btn in seedButtonList)
                        {
                            var buttonEntity = menuEntityList.FirstOrDefault(x => x.MenuType == MenuTypeEnum.Button && x.ParentId == listId && x.Name == btn.Name);
                            long buttonId = buttonEntity == null ? SnowFlakeHelper.GetLongId() : buttonEntity.Id;
                            var button = new SysMenu
                            {
                                Id = buttonId,
                                ParentId = list.Id,
                                Name = btn.Name,
                                MenuType = btn.MenuType,
                                ApiUrl = $"/api/{btn.Controller}/{btn.Action}",
                                Permission = $"api:{g.RouterName}:{btn.Controller}:{btn.Action}",
                                Icon = btn.Icon,
                                Order = btn.Order,
                                CreateTime = DateTime.Now,
                                CreateBy = userList.First().CreateBy,
                                HasChildren = false
                            };
                            if (btn.ExtraApiUrls != null)
                            {
                                button.ApiUrl = string.Join(";", btn.ExtraApiUrls.Append(button.ApiUrl));
                            }
                            menuList.Add(button);
                        }
                    }
                }
            }

            var userMenuEntityList = _db.Queryable<SysUserMenu>().ToList();
            var userMenuList = new List<SysUserMenu>();
            foreach (var menu in menuList)
            {
                foreach (var user in userList)
                {
                    var userMenuEntity = userMenuEntityList.FirstOrDefault(x => x.UserId == user.Id && x.MenuId == menu.Id);
                    if (userMenuEntity == null)
                    {
                        userMenuList.Add(new SysUserMenu
                        {
                            Id = SnowFlakeHelper.GetLongId(),
                            UserId = user.Id,
                            MenuId = menu.Id,
                            CreateTime = DateTime.Now,
                            IsDeleted = false,
                        });
                    }
                }
            }

            //不存在的新增，存在的更新
            using (var uow = _db.CreateContext(_db.Ado.IsNoTran()))
            {
                uow.Db.Storageable(userList).ExecuteCommand();
                uow.Db.Storageable(menuList).ExecuteCommand();
                uow.Db.Storageable(userMenuList).ExecuteCommand();

                uow.Commit();
            }
        }

    }

    public class MenuSeedData
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public MenuTypeEnum MenuType { get; set; }
        public string RouterName { get; set; }
        public string WebFilePath { get; set; }
        public string Controller { get; set; }
        public string Action { get; set; }
        public string[] ExtraApiUrls { get; set; }
        public int Order { get; set; }
        public string Icon { get; set; }
        public ApiGroupEnum BelongGroup { get; set; }
        public string BelongMenu { get; set; }
        public string BelongList { get; set; }
    }
}
